/* jQuery Context Menu
* Created: Dec 16th, 2009 by DynamicDrive.com. This notice must stay intact for usage 
* Author: Dynamic Drive at http://www.dynamicdrive.com/
* Visit http://www.dynamicdrive.com/ for full source code
*/
(function($){
	var jqcontextmenu={
		options:{hover:'jqhover',highlight:'jqhighlight',click:'right'},
		arrowpath: 'arrow.gif', //full URL or path to arrow image /Vender/jqcontextmenu/
		offsets: [1, -1], //additional x and y offset from mouse cursor for contextmenus
		ids: [], //ids of context menus already built (to prevent repeated building of same context menu)
		currentTarget:{},//current target elements
		actions:{},//bind click actions function(sourceTarget,clickTarget){}
		selector:'',
		bind:'contextmenu',
		positionul:function($, $ul, e){
			var istoplevel=$ul.hasClass('jqcontextmenu'); //Bool indicating whether $ul is top level context menu DIV
			var docrightedge=$(document).scrollLeft()+$(window).width()-40 ;//40 is to account for shadows in FF
			var docbottomedge=$(document).scrollTop()+$(window).height()-40;
			if (istoplevel){ //if main context menu DIV
				var x=e.pageX+this.offsets[0]; //x pos of main context menu UL
				var y=e.pageY+this.offsets[1];
				x=(x+$ul.data('dimensions').w > docrightedge)? docrightedge-$ul.data('dimensions').w : x; //if not enough horizontal room to the ridge of the cursor
				y=(y+$ul.data('dimensions').h > docbottomedge)? docbottomedge-$ul.data('dimensions').h : y;
			}
			else{ //if sub level context menu UL
				var $parentli=$ul.data('$parentliref');
				var parentlioffset=$parentli.offset();
				var x=$ul.data('dimensions').parentliw; //x pos of sub UL
				var y=0;

				x=(parentlioffset.left+x+$ul.data('dimensions').w > docrightedge)? x-$ul.data('dimensions').parentliw-$ul.data('dimensions').w : x ;//if not enough horizontal room to the ridge parent LI
				y=(parentlioffset.top+$ul.data('dimensions').h > docbottomedge)? y-$ul.data('dimensions').h+$ul.data('dimensions').parentlih : y;
			}
			$ul.css({left:x, top:y});
		},
		
		showbox:function($, $contextmenu, e){
			$.each(this.actions, function(id, item) {//rebulid menu depend on currentTarget
			  var li=$('#'+id, $contextmenu);//alert(typeof item.disabled);
			  if(item.disabled!==undefined){
				  if(item.disabled(jqcontextmenu.currentTarget,li)){
					  jqcontextmenu.disableItem(li,item);//,item.click  only remove item.click
				  }
				  else{
					  jqcontextmenu.enableItem(li,item);// rebind click event to menu if event be removed
				  }
				}
			});
			//end of before showbox

			this.currentTarget.addClass(this.options.highlight);
			$contextmenu.show();
		},

		hidebox:function($, $contextmenu){
			//$('.'+this.options.highlight,$(this.selector)).removeClass(this.options.highlight);
			$(this.selector).removeClass(this.options.highlight);
			$contextmenu.find('ul').andSelf().hide(); //hide context menu plus all of its sub ULs
		},
		enableItem:function(li,item){
			li.removeClass('jqdisabled');
			li.unbind('click');//remove all click event or will run too much times
			li.one('click', function(e) {
					var el=jqcontextmenu.currentTarget;
					jqcontextmenu.hidebox($, $('.jqcontextmenu')); //hide all context menus (and their sub ULs)
					item.click(el,li);
					return false;
			 });
		},
		disableItem:function(li,action){
			li.addClass('jqdisabled');
			li.unbind('click');//remove all click event
		},
		build:function($, $menu){
			$menu.css({display:'block', visibility:'hidden'}).appendTo(document.body);
			$menu.data('dimensions', {w:$menu.outerWidth(), h:$menu.outerHeight()}); //remember main menu's dimensions
			var $lis=$menu.find("ul").parent(); //find all LIs within menu with a sub UL
			$.each($lis.get(),function(i,v){
				var $li=$(this).css({zIndex: 1000+i});
				var $liparent=$li.parent();
				var $subul=$li.find('ul:eq(0)').css({display:'block'}); //set sub UL to "block" so we can get dimensions
				$subul.data('dimensions', {w:$subul.outerWidth(), h:$subul.outerHeight(), parentliw:this.offsetWidth, parentlih:this.offsetHeight});
				$subul.data('$parentliref', $li);//cache parent LI of each sub UL
				$li.data('$subulref', $subul); //cache sub UL of each parent LI
				$li.children("div:eq(0)").append( //add arrow images
					'<img src="'+jqcontextmenu.arrowpath+'" class="rightarrowclass" style="border:0;" />'
				);
				$li.bind('mouseenter', function(e){ //show sub UL when mouse moves over parent LI
					var $targetul=$(this).data('$subulref');
					if ($targetul.queue().length<=1){ //if 1 or less queued animations
						jqcontextmenu.positionul($, $targetul, e);
						$targetul.show();
					}
				});
				$li.bind('mouseleave', function(e){ //hide sub UL when mouse moves out of parent LI
					$(this).data('$subulref').hide();
				});
			});
			$.each(jqcontextmenu.actions, function(id, item) {
			  var li=$('#'+id, $menu);
			  li.bind('click', function(e) {
					var el=jqcontextmenu.currentTarget;
					jqcontextmenu.hidebox($, $('.jqcontextmenu')); //hide all context menus (and their sub ULs)
					item.click(el,li);
					return false;
			  });
			});

			$menu.find('ul').andSelf().css({display:'none', visibility:'visible'}); //collapse all ULs again
			$('li',$menu).bind('mouseover',function(e){
				//$(this).css('background-color','#E0EDFE');
				$(this).addClass(jqcontextmenu.options.hover);
			});
			$('li',$menu).bind('mouseout',function(e){
				//$(this).css('background-color','#FFFFFF');
				$(this).removeClass(jqcontextmenu.options.hover);
			});
			this.ids.push($menu.get(0).id); //remember id of context menu that was just built
		},

		init:function($, $target, $contextmenu){

			if (this.ids.length==0){ //only bind click event to document once
				$(document).bind("click", function(e){
					if (e.button==0){ //hide all context menus (and their sub ULs) when left mouse button is clicked
						jqcontextmenu.hidebox($, $('.jqcontextmenu'));
					}
				})
			}
			if ($.inArray($contextmenu.get(0).id, this.ids)==-1){ //if this context menu hasn't been built yet
				this.build($, $contextmenu);
				$(document).bind("click", function(e){
					if (e.button==0){ //hide all context menus (and their sub ULs) when left mouse button is clicked
						jqcontextmenu.hidebox($, $('.jqcontextmenu'));
					}
				});
			}
			if ($target.parents().filter('ul.jqcontextmenu').length>0) //if $target matches an element within the context menu markup, don't bind oncontextmenu to that element
				return;
			if(jqcontextmenu.options.click=='right'){
				jqcontextmenu.bind='contextmenu';
			}
			else if(jqcontextmenu.options.click=='left'){
				jqcontextmenu.bind='click';
			}
			$target.bind(jqcontextmenu.bind, function(e){
				jqcontextmenu.currentTarget=$(this);
				jqcontextmenu.hidebox($, $('.jqcontextmenu')); //hide all context menus (and their sub ULs)
				jqcontextmenu.positionul($, $contextmenu, e);
				jqcontextmenu.showbox($, $contextmenu, e);
				return false;
			});
		}
	}

	$.fn.addcontextmenu=function(contextmenuid,$actions,options){
		if($('#'+contextmenuid+' li').length>0){
			jqcontextmenu.selector=this.selector;
			jqcontextmenu.actions=$actions;
			$.extend(jqcontextmenu.options,options||{});

			return this.each(function(i, domEle){ //return jQuery obj
				var $target=$(this);
				jqcontextmenu.init($, $target, $('#'+contextmenuid));
			});
		}
	};
})(jQuery);
//Usage: $(elementselector).addcontextmenu('id_of_context_menu_on_page',{'edit':{click:function(source,li){}}})